package ttpasi.jgenere.chaocipher;

import java.util.ArrayList;
import java.util.List;

public class Cracker
{
  static void insertPermuted(char c, char p, char[] lt, char[] rt)
  {
    lt[0] = c;
    rt[rt.length - 1] = p;
  }

  static boolean contains(int[] values, int value)
  {
    for (int i = 0; i < values.length; i++)
    {
      if (values[i] == value)
      {
        return true;
      }
    }
    return false;
  }

  static int[] findOpenPositions(char[] lt, char[] rt)
  {
    List positions = new ArrayList();
    for (int i = 0; i < lt.length; i++)
    {
      if (lt[i] == '.' && rt[i] == '.')
      {
        positions.add(new Integer(i));
      }
    }
    int[] openPositions = new int[positions.size()];
    for (int i = 0; i < openPositions.length; i++)
    {
      openPositions[i] = ((Integer) positions.get(i)).intValue();
    }
    return openPositions;
  }

  static void insert(int position, char c, char p, char[] lt, char[] rt)
  {
    lt[position] = c;
    rt[position] = p;
  }

  static boolean contains(char[] values, char value)
  {
    for (int i = 0; i < values.length; i++)
    {
      if (values[i] == value)
      {
        return true;
      }
    }
    return false;
  }

  static int translate(char[] sourceAlphabet, char[] translatedAlphabet, char sourceChar, char translatedChar)
  {
    int position = Utils.position(sourceChar, sourceAlphabet);
    char oldTranslatedChar = translatedAlphabet[position];
    if (oldTranslatedChar != '.' && oldTranslatedChar != translatedChar)
    {
      return -1;
    }
    translatedAlphabet[position] = translatedChar;
    return position;
  }

  static void findTheAlphabets(int position, char[] ct, char[] pt, String left, String right, int[] holes)
  {
    if (position > 24)
    {
      System.out.println("<findTheAlphabets>");
      System.out.println("position: " + position);
      System.out.println(left);
      System.out.println(right);
      //      System.exit(0);
    }

    char[] lt = left.toCharArray();
    char[] rt = right.toCharArray();

    if (position >= ct.length)
    {
      System.out.println("alphabets found");
      System.exit(0);
    }

    if (position == 0)
    {
      insertPermuted(ct[position], pt[position], lt, rt);
      System.out.println("position: " + position);
      System.out.println(lt);
      System.out.println(rt);
      System.out.println("----");
      findTheAlphabets(position + 1, ct, pt, new String(lt), new String(rt), holes);
    }
    else if (contains(holes, position))
    {
      //      System.out.println("TRYING HOLE AT " + position);
      // try to put the letters of the current position into every open paired spaces in alphabets
      int[] openPositions = findOpenPositions(lt, rt);
      for (int i = 0; i < openPositions.length; i++)
      {
        int pos = openPositions[i];
        //        System.out.println(position + " - " + pos);
        char[] ltCopy = new char[lt.length];
        char[] rtCopy = new char[rt.length];
        System.arraycopy(lt, 0, ltCopy, 0, lt.length);
        System.arraycopy(rt, 0, rtCopy, 0, rt.length);
        insert(pos, ct[position], pt[position], ltCopy, rtCopy);
        Utils.permuteAlphabets(ltCopy, rtCopy, 0, pos, 13);
        //        System.out.println(ltCopy);
        //        System.out.println(rtCopy);
        //        System.out.println("----");
        findTheAlphabets(position + 1, ct, pt, new String(ltCopy), new String(rtCopy), holes);
      }
      //      System.out.println("FINISHED TRYING HOLE AT " + position);
    }
    else
    {
      // figure out which direction to translate
      // translate the correct direction
      // permute
      // iterate with position + 1

      int p;
      if (contains(rt, pt[position]))
      {
        if (contains(lt, ct[position]))
        {
          // don't insert the same char again
          // end this path if the current position doesn't translate correctly
          int posPt = Utils.position(pt[position], rt);
          int posCt = Utils.position(ct[position], lt);
          if (posPt != posCt)
          {
            //            System.out.println("translation already exists at different position");
            //            System.out.println("position: " + position);
            //            System.out.println("ct[position]: " + ct[position]);
            //            System.out.println("pt[position]: " + pt[position]);
            //            System.out.println(lt);
            //            System.out.println(rt);
            return;
          }
          p = posPt;
        }
        else
        {
          p = translate(rt, lt, pt[position], ct[position]);
        }
      }
      else if (contains(lt, ct[position]))
      {
        p = translate(lt, rt, ct[position], pt[position]);
      }
      else
      {
        //        System.out.println("failed path");
        return;
      }
      if (p == -1)
      {
        //        System.out.println("failed translation");
        //        System.out.println("position: " + position);
        //        System.out.println("ct[position]: " + ct[position]);
        //        System.out.println("pt[position]: " + pt[position]);
        //        System.out.println(lt);
        //        System.out.println(rt);
        return;
      }
      Utils.permuteAlphabets(lt, rt, 0, p, 13);
      //      if (position > 14)
      //      {
      //        System.out.println(lt);
      //        System.out.println(rt);
      //        System.out.println("----");
      //      }
      findTheAlphabets(position + 1, ct, pt, new String(lt), new String(rt), holes);
    }
  }

  //  static void rollBack(char[] left, char[] right, char[] ct, char[] pt, int position)
  //  {
  //    if (position <= 0)
  //    {
  //      return;
  //    }
  //    int zenith = 0;
  //    int nadir = 13;
  //    Utils.unrotateMiddle(left, zenith + 1, nadir);
  //    Utils.unrotateMiddle(right, zenith + 2, nadir);
  //    int prevPosition = Utils.position(ct[position - 1], left);
  //    Utils.rotate(left, zenith, prevPosition, left.length);
  //    Utils.rotate(right, zenith, (prevPosition == 0 ? right.length : prevPosition) - 1, right.length);
  //    rollBack(left, right, ct, pt, position - 1);
  //  }

  //  public static void main(String[] args) throws Exception
  //  {
  //    //    findMinSequencesWithHoles(4);
  //    //    1 sequences found.
  //    //    ----
  //    //    length: 261
  //    //    VCCPHCZQVAWFWIGHMMBTZPTGAIYZVPZDYRHJVJTBPTPJADLWDXOGULWVDGKFGETBBOHDTJVYTDIFHXHVPLUMSZBMAVKUDLORYBWYQVINUMUSCHQQBDXIDWXDPZDWPDCHCBNOATWYDCGOXBUBJVAGGOSQBBGVOCYYPIBAQBLLBBBDCSLZEMSTUWJVWLZROFVMXSLAITGBHPEKSIIEELKULQWRMPXTUUXWAIHACSMFKUGSKFZJWBJZRPZEARIQLGZUUHWJS
  //    //    ENSHRINEDINTHISARCANUMQTOWHICHNONEWHODOESNOTPOSSESSTHEKEYMAYENTERQTHEDECLARATIONOFINDEPENDENCEANDLINCOLNXSBEAUTIFULORATIONATGETTYSBURGAREHEREREJINFORMEDWITHANINVISIBLEQINTANGIBLEANDIMPERCEPTIBLESOULWJWFWBYRNEQANDMAPHJAGEFRWBEGUNAUGUSTSIXTEENQONENINETHREESEVENWZ
  //    //    holes at: 1[C,N], 3[P,H], 4[H,R], 11[F,T], 
  //
  //    //    // find the alphabets
  //    //    char[] ct = "VCCPHCZQVAWFWIGHMMBTZPTGAIYZVPZDYRHJVJTBPTPJADLWDXOGULWVDGKFGETBBOHDTJVYTDIFHXHVPLUMSZBMAVKUDLORYBWYQVINUMUSCHQQBDXIDWXDPZDWPDCHCBNOATWYDCGOXBUBJVAGGOSQBBGVOCYYPIBAQBLLBBBDCSLZEMSTUWJVWLZROFVMXSLAITGBHPEKSIIEELKULQWRMPXTUUXWAIHACSMFKUGSKFZJWBJZRPZEARIQLGZUUHWJS"        .toCharArray();
  //    //    char[] pt = "ENSHRINEDINTHISARCANUMQTOWHICHNONEWHODOESNOTPOSSESSTHEKEYMAYENTERQTHEDECLARATIONOFINDEPENDENCEANDLINCOLNXSBEAUTIFULORATIONATGETTYSBURGAREHEREREJINFORMEDWITHANINVISIBLEQINTANGIBLEANDIMPERCEPTIBLESOULWJWFWBYRNEQANDMAPHJAGEFRWBEGUNAUGUSTSIXTEENQONENINETHREESEVENWZ"        .toCharArray();
  //    //    //           01234567890123456789
  //    //
  //    //    String lt = "..........................";
  //    //    String rt = "..........................";
  //    //
  //    //    int[] holes = {1, 3, 4, 11};
  //    //
  //    //    initializeLogging();
  //    //    findTheAlphabets(0, ct, pt, lt, rt, holes);
  //    char[] left = "SOBFHUJKVQXYRADCEPMWGZLTNI".toCharArray();
  //    char[] right = "XEFIWLPGOHSRCVATNYDJBMQKUZ".toCharArray();
  //    //
  //    //    // roll the alphabets back to position 1
  //    //    rollBack(left, right, ct, pt, 260);
  //    //    System.out.println(left); //  VEYKGTMHISAUXCPODWFQBZJLRN
  //    //    System.out.println(right); // CXHJMYWKVBRUPNSQFGTIOLDZAE
  //
  //    //           Z            N
  //    //    String lt = "VCEYKGTMHISAUXPODWFQBZJLRN";
  //    //    String rt = "ECXNHJMYWKVBRUPSQFGTIOLDZA";
  //    //    
  //    //    Chaocipher chaocipher = new Chaocipher(lt, rt);
  //    //    String ciphertext = chaocipher.encipher(new String(pt));
  //    //    System.out.println(ciphertext);
  //    //    String plaintext = chaocipher.decipher(new String(ct));
  //    //    System.out.println(plaintext);
  //
  //    // roll the alphabets all the way back to position 1 of the entire text
  //    String ct = read("test-data/chaocipher-exhibit-1.cracked.ct.txt");
  //    String pt = read("test-data/chaocipher-exhibit-1.cracked.pt.txt");
  //    rollBack(left, right, ct.toCharArray(), pt.toCharArray(), 5761);
  //    System.out.println(left); //  CEDQRSTIXYLMOPZABFVGUHWJKN
  //    System.out.println(right); // YZBQDSEFGHLWINKCMOPRTUVJXA
  //
  //    //           Z            N
  //    String lt = "CPEDQRSTIXYLMOZABFVGUHWJKN"; // CPEDQRSTIXYLMOZABFVGUHWJKN
  //    String rt = "AYZNBQDSEFGHLWIKCMOPRTUVJX"; // AYZNBQDSEFGHLWIKCMOPRTUVJX
  //
  //    // CLY
  //    // ALL
  //  }
}
